﻿using HalconDotNet;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;

namespace BindingWPF
{
    public class ViewModel : DependencyObject, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private HObject _displayImage;
        public HObject DisplayImage
        {
            get { return _displayImage; }
            set { _displayImage = value; NotifyPropertyChanged("DisplayImage"); DisplayRegion = null; }
        }

        private HObject _displayRegion;
        public HObject DisplayRegion
        {
            get { return _displayRegion; }
            set { _displayRegion = value; NotifyPropertyChanged("DisplayRegion"); }
        }
        
        public int MinThreshold
        {
            get { return (int)GetValue(MinThresholdProperty); }
            set { SetValue(MinThresholdProperty, value); }
        }
        public static readonly DependencyProperty MinThresholdProperty =
            DependencyProperty.Register("MinThreshold", typeof(int), typeof(ViewModel), new PropertyMetadata(0, new PropertyChangedCallback(OnThresholdValueChanged)));

        public int MaxThreshold
        {
            get { return (int)GetValue(MaxThresholdProperty); }
            set { SetValue(MaxThresholdProperty, value); }
        }
        public static readonly DependencyProperty MaxThresholdProperty =
            DependencyProperty.Register("MaxThreshold", typeof(int), typeof(ViewModel), new PropertyMetadata(128, new PropertyChangedCallback(OnThresholdValueChanged)));

        private static void OnThresholdValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            ViewModel vm = obj as ViewModel;
            if (vm != null)
            {
                if (e.Property.Name == "MinThreshold" && (int)e.NewValue > vm.MaxThreshold)
                    vm.MaxThreshold = (int)e.NewValue;
                if (e.Property.Name == "MaxThreshold" && (int)e.NewValue < vm.MinThreshold)
                    vm.MinThreshold = (int)e.NewValue;
                if (vm.DisplayRegion != null && vm.DisplayImage != null)
                    vm.DisplayRegion = ((HImage)vm.DisplayImage).Threshold((double)vm.MinThreshold, (double)vm.MaxThreshold);
            }
        }
        public SimpleCommand LoadFabrik
        {
            get; private set;
        }

        public SimpleCommand LoadPCB
        {
            get; private set;
        }
        public SimpleCommand ApplyThreshold
        { get; private set; }

        public ViewModel()
        {
            // Define the functions that are called through the Commands assigned to
            // the buttons.
            // The Load buttons simply load a new image.
            LoadFabrik = new SimpleCommand((obj) => DisplayImage = new HImage("fabrik"));
            LoadPCB = new SimpleCommand((obj) => DisplayImage = new HImage("pcb_layout"));
            // The Apply button is only enabled when an image was loaded
            ApplyThreshold = new SimpleCommand(
                (obj) => {
                    if (DisplayImage != null)
                        DisplayRegion = ((HImage)DisplayImage).Threshold((double)MinThreshold, (double)MaxThreshold);
                },
                (obj)=>DisplayImage!=null);
        }

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public class SimpleCommand : ICommand
    {
        private Action<object> _execute;

        private Predicate<object> _canExecute;
        private event EventHandler _canExecuteChanged;
        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
                _canExecuteChanged += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
                _canExecuteChanged -= value;
            }
        }
        protected virtual void OnCanExecuteChanged(EventArgs e)
        {
            if (_canExecuteChanged != null)
                _canExecuteChanged.Invoke(this, EventArgs.Empty);
        }

        public SimpleCommand(Action<object> execute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = ((obj) => true);
        }
        public SimpleCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            if (canExecute == null)
                throw new ArgumentNullException("canExecute");

            _execute = execute;
            _canExecute = canExecute;
        }
        public bool CanExecute(object parameter)
        {
            return _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}
